/*
 * Copyright © 2004-2014 chenYuan. All rights reserved.
 * @Website:wwww.jspx.net
 * @Mail:39793751@qq.com
 * @author: chenYuan , 陈原
 * @License: Jspx.net Framework Code is open source (LGPL)，Jspx.net Framework 使用LGPL 开源授权协议发布。
 * @jvm:jdk1.6+  x86/amd64
 *
 */
package com.jspx.boot.environment.impl;


import com.jspx.boot.environment.Environment;
import com.jspx.boot.environment.EnvironmentTemplate;
import com.jspx.boot.environment.Placeholder;
import com.jspx.io.AbstractRead;
import com.jspx.io.AutoReadTextFile;
import com.jspx.security.symmetry.impl.XOREncrypt;
import com.jspx.utils.FileUtil;
import com.jspx.utils.StringUtil;
import com.jspx.utils.SystemUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.*;



/**
 * Created by IntelliJ IDEA.
 * User:chenYuan (mail:39793751@qq.com)
 * Date: 2006-8-4
 * Time: 0:19:29
 */
public class EnvironmentTemplateImpl implements EnvironmentTemplate {
    static private final Logger log = LoggerFactory.getLogger(EnvironmentTemplateImpl.class);
    static private Placeholder placeholder = new PlaceholderImpl();
    private static final Map<String, Object> valueMap = new Hashtable<String, Object>();

    public EnvironmentTemplateImpl() {

    }

    public Map<String, Object> getVariableMap() {
        Map<String, Object> result  = new Hashtable<String, Object>();
        for (String key:valueMap.keySet())
        {
            if (StringUtil.isNULL(key) || key.contains(".")) continue;
            result.put(key,valueMap.get(key));
        }
        return result;
    }

    public void put(String keys, Object value) {
        valueMap.put(keys, value);
    }

    public Object get(String keys) {
        return valueMap.get(keys);
    }

    public String getString(String key) {
        Object o = valueMap.get(key);
        if (o == null) return System.getProperty(key);
        return o.toString();
    }

    public String getString(String keys, String def) {
        String result = getString(keys);
        if (!StringUtil.hasLength(result)) return def;
        return result;
    }

    public boolean getBoolean(String keys) {
        return StringUtil.toBoolean(getString(keys));
    }

    public int getInt(String keys) {
        return StringUtil.toInt(getString(keys));
    }

    public int getInt(String keys, int def) {
        return StringUtil.toInt(getString(keys), def);
    }

    public long getLong(String keys, long def)
    {
        return StringUtil.toLong(getString(keys), def);
    }

    public String processTemplate(String templateString) throws Exception {

        return placeholder.processTemplate(valueMap, templateString);
    }

    /**
     06-14 01:50:18.755     java.vm.specification.vendor=The Android Project
     06-14 01:50:18.755     java.vm.name=Dalvik
     06-14 01:50:18.755     java.vm.specification.version=0.9
     06-14 01:50:18.755     java.vendor.url=http://www.android.com/
     06-14 01:50:18.755     user.home=
     06-14 01:50:18.755     java.ext.dirs=
     06-14 01:50:18.755     java.specification.name=Dalvik Core Library
     06-14 01:50:18.755     line.separator=
     06-14 01:50:18.755     file.encoding=UTF-8
     06-14 01:50:18.755     java.runtime.version=0.9
     06-14 01:50:18.755     user.name=
     06-14 01:50:18.755     file.separator=/
     06-14 01:50:18.755     java.library.path=/vendor/lib:/system/lib
     06-14 01:50:18.755     java.compiler=
     06-14 01:50:18.755     os.version=3.0.31-2218247
     06-14 01:50:18.755     android.icu.unicode.version=6.2
     06-14 01:50:18.755     java.boot.class.path=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/framework2.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/sec_edm.jar:/system/framework/seccamera.jar:/system/framework/scrollpause.jar:/system/framework/stayrotation.jar:/system/framework/smartfaceservice.jar:/system/framework/sc.jar:/system/framework/secocsp.jar:/system/framework/commonimsinterface.jar
     06-14 01:50:18.755     java.vm.specification.name=Dalvik Virtual Machine Specification
     06-14 01:50:18.755     java.version=0
     06-14 01:50:18.755     android.icu.library.version=50.1.1.3
     06-14 01:50:18.755     os.name=Linux
     06-14 01:50:18.755     user.region=CN
     06-14 01:50:18.755     os.arch=armv7l
     06-14 01:50:18.755     java.class.path=.
     06-14 01:50:18.755     java.io.tmpdir=/data/data/com.jspx.android.jtrace/cache
     06-14 01:50:18.755     android.zlib.version=1.2.7
     06-14 01:50:18.755     user.language=zh
     06-14 01:50:18.755     java.vm.version=1.6.0
     06-14 01:50:18.755     java.specification.vendor=The Android Project
     06-14 01:50:18.755     java.vm.vendor=The Android Project
     06-14 01:50:18.755     java.vendor=The Android Project
     06-14 01:50:18.755     http.agent=Dalvik/1.6.0 (Linux; U; Android 4.3; GT-I9308 Build/JSS15J)
     06-14 01:50:18.755     android.icu.cldr.version=22.1.1
     06-14 01:50:18.755     android.openssl.version=OpenSSL 1.0.1e 11 Feb 2013
     06-14 01:50:18.755     path.separator=:
     06-14 01:50:18.755     java.runtime.name=Android Runtime
     06-14 01:50:18.755     java.specification.version=0.9
     06-14 01:50:18.755     user.dir=/
     06-14 01:50:18.755     java.vm.vendor.url=http://www.android.com/
     06-14 01:50:18.755     java.home=/system
     06-14 01:50:18.755     java.class.version=50.0
     06-14 01:50:18.755     -------------------env
     06-14 01:50:18.760     ANDROID_SOCKET_zygote=9
     06-14 01:50:18.760     EMULATED_STORAGE_SOURCE=/mnt/shell/emulated
     06-14 01:50:18.760     SECONDARY_STORAGE=/storage/extSdCard
     06-14 01:50:18.760     ANDROID_STORAGE=/storage
     06-14 01:50:18.760     ANDROID_BOOTLOGO=1
     06-14 01:50:18.760     EXTERNAL_STORAGE=/storage/emulated/legacy
     06-14 01:50:18.760     ANDROID_ASSETS=/system/app
     06-14 01:50:18.760     ASEC_MOUNTPOINT=/mnt/asec
     06-14 01:50:18.760     PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
     06-14 01:50:18.760     LOOP_MOUNTPOINT=/mnt/obb
     06-14 01:50:18.760     BOOTCLASSPATH=/system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/framework2.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar:/system/framework/sec_edm.jar:/system/framework/seccamera.jar:/system/framework/scrollpause.jar:/system/framework/stayrotation.jar:/system/framework/smartfaceservice.jar:/system/framework/sc.jar:/system/framework/secocsp.jar:/system/framework/commonimsinterface.jar
     06-14 01:50:18.760     EMULATED_STORAGE_TARGET=/storage/emulated
     06-14 01:50:18.760     ANDROID_DATA=/data
     06-14 01:50:18.760     ANDROID_PROPERTY_WORKSPACE=8,66560
     06-14 01:50:18.760     ANDROID_ROOT=/system
     06-14 01:50:18.760     LD_LIBRARY_PATH=/vendor/lib:/system/lib
     06-14 01:50:18.760     VIBE_PIPE_PATH=/dev/pipes
     * @param defaultPath 默认路径
     * @throws Exception
     */

    public void createPathEnv(String defaultPath) throws Exception {
        //DefaultPath
        valueMap.put(Environment.defaultPath, defaultPath);
        valueMap.put(Environment.ConfigFile, defaultPath + Environment.config_file);
        String logPath = System.getProperty("java.io.tmpdir");
        if (SystemUtil.isAndroid())
        {
            //安卓方式目录环境
            String tmpDir = FileUtil.mendPath(System.getProperty("java.io.tmpdir"));
            logPath = tmpDir;
            valueMap.put(Environment.templatePath, defaultPath);
            valueMap.put(Environment.loaderPath, defaultPath);
            valueMap.put(Environment.resPath, defaultPath);
            valueMap.put(Environment.cachePath, tmpDir);
            valueMap.put(Environment.tempPath,tmpDir);

        } else {
            //WebInfPath
            String webInfPath;
            if (defaultPath != null && defaultPath.toLowerCase().contains("file-inf")) {
                ///jsp方式
                webInfPath = defaultPath.substring(0, defaultPath.toLowerCase().indexOf("file-inf/") + 8);
            } else if (defaultPath != null && defaultPath.contains(".jar") || defaultPath != null && defaultPath.contains(".zip") || defaultPath != null && defaultPath.contains(".apk")) {
                //////////文件在jar目录中的情况
                webInfPath = FileUtil.getParentPath(FileUtil.getPathPart(StringUtil.substringBefore(defaultPath, "!/")));
            } else {
                webInfPath = FileUtil.getParentPath(defaultPath);
            }
            webInfPath = FileUtil.mendPath(webInfPath);
            valueMap.put(Environment.webInfPath, webInfPath);
            String tempDir = webInfPath + "template/";
            if (!FileUtil.isDirectory(tempDir)) FileUtil.makeDirectory(tempDir);
            if (!valueMap.containsKey(Environment.templatePath)) {
                valueMap.put(Environment.templatePath, tempDir);
            }

            //loader路径
            tempDir = webInfPath + "loader/";
            //FileUtil.makeDirectory(tempDir);
            valueMap.put(Environment.loaderPath, tempDir);

            //LucenePath     得到默认的Lucene 目录,应为文件放在外部不安全
            tempDir = webInfPath + "lucene/";
            //FileUtil.makeDirectory(tempDir);
            valueMap.put(Environment.lucenePath, tempDir);

            //本地数据库默认路径
            tempDir = webInfPath + "database/";
            FileUtil.makeDirectory(tempDir);
            valueMap.put(Environment.databasePath, tempDir);

            //LibPath    得到库文件路径
            tempDir = webInfPath + "lib/";
            FileUtil.makeDirectory(tempDir);
            valueMap.put(Environment.libPath, tempDir);

            //PluginsPath    插件目录
            tempDir = webInfPath + "plugins/";
            //FileUtil.makeDirectory(tempDir);
            valueMap.put(Environment.pluginsPath, tempDir);

            //fontsPath    字体目录
            tempDir = webInfPath + "fonts/";
            //FileUtil.makeDirectory(tempDir);
            valueMap.put(Environment.fontsPath, tempDir);

            //ResPath    资源目录
            tempDir = webInfPath + "reslib/";
            FileUtil.makeDirectory(tempDir);
            valueMap.put(Environment.resPath, tempDir);

            //CachePath    缓存目录
            tempDir = webInfPath + "cache/";
            FileUtil.makeDirectory(tempDir);
            valueMap.put(Environment.cachePath, tempDir);

            //升级文件保存目录
            tempDir = webInfPath + "upgrade/";
            //FileUtil.makeDirectory(tempDir);
            valueMap.put(Environment.upgradePath, tempDir);

            //TempPath    临时路径
            tempDir = webInfPath + "tmp/";
            if (FileUtil.isDirectory(tempDir)) {
                valueMap.put(Environment.tempPath, tempDir);
            } else {
                valueMap.put(Environment.tempPath, FileUtil.mendPath(System.getProperty("java.io.tmpdir")));
            }

            //Log4jPath
            logPath = getLog4jPath((String) valueMap.get(Environment.logPath));
            if (!StringUtil.isNULL(logPath)) {
                valueMap.put(Environment.log4jPath, logPath);
            } else {
                //LogPath    日志保存目录
                logPath = webInfPath + "logs/";
                if (!FileUtil.isDirectory(tempDir)) FileUtil.makeDirectory(tempDir);
                valueMap.put(Environment.logPath, logPath);
            }
        }

        valueMap.put(Environment.logInfoFile, logPath + Environment.log_info_file);

        valueMap.put(Environment.logErrorFile, logPath + Environment.log_error_file);

        valueMap.put(Environment.logJspxInfoFile, logPath + Environment.log_jspx_info_file);

        valueMap.put(Environment.logJspxDebugFile, logPath + Environment.log_jspx_debug_file);

        valueMap.put(Environment.logJspxErrorFile, logPath + Environment.log_jspx_error_file);
    }

    private String getEncode() {

        String encode = (String) valueMap.get(Environment.encode);
        if (StringUtil.isNULL(encode)) encode = System.getProperty("file.encoding");
        if (StringUtil.isNULL(encode)) return Environment.defaultEncode;
        return encode;
    }

    private String getTimezone() {
        return (String) valueMap.get(Environment.timezone);
    }

    private String getAwtToolkit() {
        String awtToolkit = (String) valueMap.get("awt.toolkit");
        if (awtToolkit == null || awtToolkit.length() < 1) return System.getProperty("awt.toolkit");
        return awtToolkit;
    }

    private Object getJava2dUsePlatformFont() {
        if (valueMap.containsKey("java2d.font.usePlatformFont")) {
            return valueMap.get("java2d.font.usePlatformFont");
        }
        return System.getProperty("java2d.font.usePlatformFont");
    }

    private Object getGraphicsenv() {
        if (valueMap.containsKey("java.awt.graphicsenv")) {
            return valueMap.get("java.awt.graphicsenv");
        }
        return System.getProperty("java.awt.graphicsenv");
    }

    private String getLog4jPath(String log4jPath) throws Exception {
        if (log4jPath == null) return null;
        File f = new File(log4jPath);
        if (f.isDirectory()) return FileUtil.mendPath(f.getAbsolutePath());
        if (!StringUtil.isNULL(log4jPath) && log4jPath.contains("$")) {
            try {
                return processTemplate(log4jPath);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 正相和反相的设置环境变量
     */
    public void createSystemEnv() {
        //encode
        if (!SystemUtil.isAndroid())
            System.setProperty("file.encoding", getEncode());


        System.setProperty("javax.xml.soap.character-set-encoding", getEncode());
        //awtToolkit
        String awtToolkit = getAwtToolkit();
        if (!StringUtil.isNULL(awtToolkit)) {
            System.setProperty("awt.toolkit", awtToolkit);
        }
        //java2dUsePlatformFont
        String usePlatformFont = (String) getJava2dUsePlatformFont();
        if (!StringUtil.isNULL(usePlatformFont)) {
            System.setProperty("java2d.font.usePlatformFont", usePlatformFont);
        }
        //graphicsenv
        String getGraphicsenv = (String) getGraphicsenv();
        if (!StringUtil.isNULL(getGraphicsenv)) {
            System.setProperty("java.awt.graphicsenv", getGraphicsenv);
        }

        //设置时区
        String timezone = getTimezone();
        if (!StringUtil.isNULL(timezone)) {
            System.setProperty("user.timezone", timezone);
        }

        if (valueMap.containsKey(Environment.cachePath))
            System.setProperty(Environment.cachePath, (String) valueMap.get(Environment.cachePath));

        //系统密钥
        if (valueMap.containsKey(Environment.secretKey))
            System.setProperty(Environment.secretKey, (String) valueMap.get(Environment.secretKey));

        //对称加密算法
        if (valueMap.containsKey(Environment.symmetryAlgorithm))
            System.setProperty(Environment.symmetryAlgorithm, (String) valueMap.get(Environment.symmetryAlgorithm));

        //对称加密算法偏移量
        if (valueMap.containsKey(Environment.cipherIv))
            System.setProperty(Environment.cipherIv, (String) valueMap.get(Environment.cipherIv));

        //非对称加密算法
        if (valueMap.containsKey(Environment.asymmetricAlgorithm))
            System.setProperty(Environment.asymmetricAlgorithm, (String) valueMap.get(Environment.asymmetricAlgorithm));

        //非对称验证算法  如 SHA1WithRSA
        if (valueMap.containsKey(Environment.signAlgorithm))
            System.setProperty(Environment.signAlgorithm, (String) valueMap.get(Environment.signAlgorithm));

        //验证加密算法 如md5
        if (valueMap.containsKey(Environment.hashAlgorithm))
            System.setProperty(Environment.hashAlgorithm, (String) valueMap.get(Environment.hashAlgorithm));


        Enumeration enumeration = System.getProperties().keys();
        while (enumeration.hasMoreElements()) {
            String keys = (String) enumeration.nextElement();
            if (System.getProperty(keys)!=null)
                valueMap.put(keys, System.getProperty(keys));
        }


        //监测当前的web 服务器 begin
        if (Environment.auto.equalsIgnoreCase((String) valueMap.get(Environment.repairEncode)) || !valueMap.containsKey(Environment.repairEncode))
            try {
                Class.forName("org.apache.catalina.Server", true, Thread.currentThread().getContextClassLoader());
                valueMap.put(Environment.httpServerName, Environment.webServerTomcat);
                valueMap.put(Environment.repairEncode, "true");
            } catch (Exception e) {
                valueMap.put(Environment.repairEncode, "false");
                valueMap.put(Environment.httpServerName, Environment.webServerResin);
            }
        //监测当前的web 服务器 end
        if (valueMap.containsKey("javax.xml.stream.XMLInputFactory"))
        try {
            Class.forName("com.sun.xml.internal.stream.XMLInputFactoryImpl");
            System.setProperty("javax.xml.stream.XMLInputFactory", "com.sun.xml.internal.stream.XMLInputFactoryImpl");
        } catch (Exception e) {
            log.info("com.sun.xml.internal.stream.XMLInputFactoryImpl "+ e.getLocalizedMessage());
            //LoggerFactory.printError("not found xercesImpl.jar,没有找到 xercesImpl.jar",e);
        }
        if (SystemUtil.isAndroid())
            try {
                Class.forName("org.apache.xerces.parsers.SAXParser");
                System.setProperty("org.xml.sax.driver", "org.apache.xerces.parsers.SAXParser");
            } catch (Exception e) {
                log.info("not found xercesImpl.jar,没有找到 xercesImpl.jar " + e.getLocalizedMessage());
            }
    }


    @SuppressWarnings("unchecked")
    public void createJspxEnv(String fileName) {
        try
        {
            AbstractRead abstractRead = new AutoReadTextFile();
            abstractRead.setEncode(Environment.defaultEncode);
            abstractRead.setFile(fileName);
            String cont = abstractRead.getContent();

            XOREncrypt encrypt = new XOREncrypt();
            encrypt.setSecretKey(Environment.defaultDrug);
            if (encrypt.isEncrypt(cont))
            {
                cont = encrypt.getDecode(cont);
            }

            Properties p = new Properties();
            p.load(new StringReader(cont));

            if (!Environment.defaultEncode.equalsIgnoreCase((String) p.get(Environment.encode))) {  //修正配置文件编码
                abstractRead.setEncode((String) p.get(Environment.encode));
                p.load(new StringReader(abstractRead.getContent()));
            }
            for (Object key:p.keySet())
            {
                Object o = p.get(key);
                if (o==null) continue;
                valueMap.put((String)key,o);
            }
            valueMap.put(Environment.jspxProperties, fileName);
            p.clear();
        } catch (Exception e) {
            log.info("create Jspx.net Env fileName=" + fileName + " " + e.getLocalizedMessage());
            e.printStackTrace();
        }
        //创建配置 begin

    }

    public void restorePlaceholder() throws Exception {
        Iterator<String> iterator  =valueMap.keySet().iterator();
        while (iterator.hasNext())
        {
            String key = iterator.next();
            Object o = valueMap.get(key);
            if (StringUtil.isNULL(key)) continue;
            if (o != null) {
                String value = o.toString();
                synchronized (valueMap)
                {
                    valueMap.put(key, processTemplate(value));
                }
            }
        }
    }

    public Properties getProperties() {
        Properties p = new Properties();
        for (String key : valueMap.keySet()) {
            Object o = valueMap.get(key);
            if (StringUtil.isNULL(key)) continue;
            if (o != null) {
                p.setProperty(key, o.toString());
            }
        }
        return p;
    }

    public void debugPrint() {
        for (String key : valueMap.keySet()) {
            Object o = valueMap.get(key);
            if (StringUtil.isNULL(key)) continue;
            if (o != null) {
                log.info(key + "=" + o.toString());
            }
        }

    }
}